package com.tlgen.modules.dept.service.impl;

import com.tlgen.common.exception.BadRequestException;
import com.tlgen.common.exception.EntityExistException;
import com.tlgen.common.utils.FileUtil;
import com.tlgen.common.utils.QueryHelp;
import com.tlgen.common.utils.ValidationUtil;
import com.tlgen.modules.dept.domain.Subject;
import com.tlgen.modules.dept.repository.SubjectRepository;
import com.tlgen.modules.dept.service.SubjectService;
import com.tlgen.modules.dept.service.dto.SubjectDto;
import com.tlgen.modules.dept.service.dto.SubjectQueryCriteria;
import com.tlgen.modules.dept.service.mapper.SubjectMapper;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;

/**功能描述：科室
 */
@Service
@CacheConfig(cacheNames = "subject")
@Transactional(propagation = Propagation.SUPPORTS, readOnly = true, rollbackFor = Exception.class)
public class SubjectServiceImpl implements SubjectService {

    private final SubjectRepository subjectRepository;

    private final SubjectMapper subjectMapper;

    public SubjectServiceImpl(SubjectRepository subjectRepository, SubjectMapper subjectMapper) {
        this.subjectRepository = subjectRepository;
        this.subjectMapper = subjectMapper;
    }

    @Override
    public Map<String, Object> buildTree(List<SubjectDto> subjectDtos) {
        List<SubjectDto> trees = new ArrayList<>();
        Set<Long> ids = new HashSet<>();
        for (SubjectDto subjectDTO : subjectDtos) {
            if (subjectDTO.getPid() == 0) {
                trees.add(subjectDTO);
            }
            for (SubjectDto it : subjectDtos) {
                if (it.getPid().equals(subjectDTO.getId())) {
                    if (subjectDTO.getChildren() == null) {
                        subjectDTO.setChildren(new ArrayList<>());
                    }
                    subjectDTO.getChildren().add(it);
                    ids.add(it.getId());
                }
            }
        }
        Map<String, Object> map = new HashMap<>(2);
        if (trees.size() == 0) {
            trees = subjectDtos.stream().filter(s -> !ids.contains(s.getId())).collect(Collectors.toList());
        }
        map.put("content", trees);
        map.put("totalElements", subjectDtos.size());
        return map;
    }

    @Override
    public List<SubjectDto> buildSubjects(List<SubjectDto> subjectDtos) {
        List<SubjectDto> list = new LinkedList<>();
        subjectDtos.forEach(subjectDTO -> {
            List<SubjectDto> jAreaDtoList = new LinkedList<>();
            SubjectDto subjectDto = new SubjectDto();
            subjectDto.setChildren(buildSubjects(jAreaDtoList));
            list.add(subjectDto);

        });
        return list;
    }

    @Override
    public List<SubjectDto> queryAll(SubjectQueryCriteria criteria) {
        return subjectMapper.toDto(subjectRepository.findAll(((root, criteriaQuery, criteriaBuilder) ->
                QueryHelp.getPredicate(root, criteria, criteriaBuilder))));
    }

    @Override
    @Cacheable(key = "'pid:'+#p0")
    public List<Subject> findByPid(long pid) {
        return subjectRepository.findByPid(pid);
    }

    @Override
    @Cacheable(key = "'tree'")
    public Object getSubjectTree(List<Subject> subjects) {
        List<Map<String, Object>> list = new LinkedList<>();
        subjects.forEach(subject -> {
            if (subject != null) {
                List<Subject> subjectList = subjectRepository.findByPid(subject.getId());
                Map<String, Object> map = new HashMap<>(16);
                map.put("id", subject.getId());
                map.put("label", subject.getName());
                map.put("pid", subject.getPid());
                if (subjectList != null && subjectList.size() != 0) {
                    map.put("children", getSubjectTree(subjectList));
                }
                list.add(map);
            }
        });
        return list;
    }

    @Override
    @CacheEvict(allEntries = true)
    public SubjectDto create(Subject resources) {
        return subjectMapper.toDto(subjectRepository.save(resources));
    }

    @Override
    @CacheEvict(allEntries = true)
    public void update(Subject resources) {
        if (resources.getId().equals(resources.getPid())) {
            throw new BadRequestException("上级不能为自己!");
        }
        Subject subject = subjectRepository.findById(resources.getId()).orElseGet(Subject::new);
        ValidationUtil.isNull(subject.getId(), "id", "id", resources.getId());

        Subject subject1 = subjectRepository.findByName(resources.getName());
        if (subject1 != null && !subject1.getId().equals(subject.getId())) {
            throw new EntityExistException(Subject.class, "county", resources.getName());
        }
        subject.setName(resources.getName());
        subject.setPid(resources.getPid());
        subjectRepository.save(subject);
    }

    @Override
    public Set<Subject> getDeleteSubjects(List<Subject> subjectList, Set<Subject> subjectSet) {
        for (Subject subject : subjectList) {
            subjectSet.add(subject);
            List<Subject> subjects = subjectRepository.findByPid(subject.getId());
            if (subjects != null && subjects.size() !=0) {
                getDeleteSubjects(subjects, subjectSet);
            }
        }
        return subjectSet;
    }

    @Override
    public Subject findOne(Long id) {
        Subject subject = subjectRepository.findById(id).orElseGet(Subject::new);
        ValidationUtil.isNull(subject.getId(), "subject", "id", id);
        return subject;
    }

    @Override
    @CacheEvict(allEntries = true)
    @Transactional(rollbackFor = Exception.class)
    public void delete(Set<Subject> subjectSet) {
        for (Subject subject : subjectSet) {
            subjectRepository.deleteById(subject.getId());
        }
    }

    @Override
    public void download(List<SubjectDto> queryAll, HttpServletResponse response) throws IOException {
        List<Map<String, Object>> list = new ArrayList<>();
        for (SubjectDto subjectDto : queryAll) {
            Map<String,Object> map = new LinkedHashMap<>();
            map.put("科室", subjectDto.getName());
            map.put("父编号", subjectDto.getPid());
            map.put("子科室", subjectDto.getChildren());
            list.add(map);
        }
        FileUtil.downloadExcel(list, response);
    }

}
